/// <reference path="./Block.ts" />

namespace tetris {
    import IPoint = model.IPoint;
    import BlockPoint = model.BlockPoint;

    type JQueryArray = Array<JQuery>;
    type JQueryMatrix = Array<JQueryArray>;

    function createCell(): JQuery {
        return $("<span>").addClass("block");
    }

    interface IRow {
        row: JQuery,
        blocks: JQueryArray;
    }

    function createRow(blockCount: number): IRow {
        const div = $("<div>").addClass("row");
        const blocks = Array<JQuery>(blockCount);
        for (let i = 0; i < blockCount; i++) {
            const block = blocks[i] = createCell();
            div.append(block);
        }

        return {
            row: div,
            blocks: blocks
        };
    }

    export class Puzzle {
        block: Block | null;
        fastened: Array<BlockPoint>;

        private _width: number;
        private _height: number;
        private _matrix: JQueryMatrix;

        constructor(width: number, height: number) {
            this._width = width;
            this._height = height;
            this.block = null;
            this.fastened = [];
        }

        get width() {
            return this._width;
        }

        get height() {
            return this._height;
        }

        getCell(point: IPoint): JQuery;
        getCell(x: number, y: number): JQuery;
        getCell(x: IPoint | number, y: number = 0): JQuery {
            if (typeof x === "object") {
                y = x.y;
                x = x.x;
            }

            if (x >= this.width || y >= this.height) {
                return $();
            }

            return this._matrix[y][x];
        }

        build(): JQueryArray;
        build(container: JQuery): Puzzle;
        build(container?): Puzzle | JQueryArray {
            const rows: Array<IRow> = [];

            for (let i = 0; i < this.height; i++) {
                rows[i] = createRow(this.width);
            }

            this._matrix = rows.map(row => row.blocks);

            const divs = rows.map(row => row.row);
            if (container) {
                container.append(divs);
                return this;
            }
            return divs;
        }

        render() {
            this._matrix.forEach(row => {
                row.forEach(block => {
                    block.removeClass().addClass("block");
                });
            });

            this.fastened.forEach(bPoint => this.getCell(bPoint).addClass(bPoint.c));

            if (this.block) {
                this.block.fasten().forEach(bPoint => this.getCell(bPoint).addClass(bPoint.c));
            }
        }
    }
}